/*
 *  ifxvariable.hpp - Informix variable and value classes
 *
 *    Copyright (c) 2001-2006, Luxena Software Company. All rights reserved.
 *
 *  Purpose:
 *
 */

#ifndef __IFXVARIABLE_HPP__
#define __IFXVARIABLE_HPP__

#ifndef __cplusplus
#error This header requires a C++ compiler ...
#endif

#include <sqltypes.h>
#include <int8.h>
#include <decimal.h>
#include <datetime.h>
#include "dbxpress.hpp"
#include "ifxdefs.hpp"
#include "ifxerror.hpp"


/////////////////////////////////////////////////////////////////////////////
// CInformixAbstractValue

class CInformixAbstractValue
{
public:
	virtual ~CInformixAbstractValue () {}

	virtual int2 getType () = 0;
	virtual int4 getLength () = 0;
	virtual char * getData () = 0;
	virtual int2 getXID () { return 0; }
	virtual char * getTypeName () { return 0; }
	virtual int2 getTypeNameLength () { return 0; }

	virtual void asString (char *value) { throw CInvalidCastError(); }
	virtual double asDouble () { throw CInvalidCastError(); }
	virtual FMTBcd& asFMTBcd () { throw CInvalidCastError(); }
};


/////////////////////////////////////////////////////////////////////////////
// Fetch observing classes

struct IFetchObserver
{
	virtual void update () = 0;
};

struct IFetchSubject
{
	typedef IFetchObserver * Observer;
	virtual void attach (Observer observer) = 0;
	virtual void notify () = 0;
};


/////////////////////////////////////////////////////////////////////////////
// CInformixSimpleValue

template <typename ValueType>
class CInformixAbstractSimpleValue : public CInformixAbstractValue
{
public:
	CInformixAbstractSimpleValue () {}
	CInformixAbstractSimpleValue (ValueType value): _value(value) {}
	virtual int4 getLength () { return sizeof(_value); }
	virtual char * getData () { return reinterpret_cast<char *>(&_value); }
	virtual double asDouble () { return _value; }
	operator ValueType& () { return _value; }
private:
	ValueType _value;
};

template <typename ValueType, int2 InformixType>
class CInformixSimpleValue : public CInformixAbstractSimpleValue<ValueType>
{
public:
	CInformixSimpleValue () {}
	CInformixSimpleValue (ValueType value): CInformixAbstractSimpleValue<ValueType>(value) {}
	virtual int2 getType () { return InformixType; }
};


/////////////////////////////////////////////////////////////////////////////
// CInformixStringValue

class CInformixAbstractStringValue : public CInformixAbstractValue
{
public:
	CInformixAbstractStringValue (int4 length);
	CInformixAbstractStringValue (int4 length, char *value);
	virtual ~CInformixAbstractStringValue ();
	virtual int4 getLength ();
	virtual char * getData ();
	virtual void asString (char *value);
	operator char * ();
private:
	int4 _length;
	char *_value;
};

template <int2 InformixType>
class CInformixStringValue : public CInformixAbstractStringValue
{
public:
	CInformixStringValue (int4 length): CInformixAbstractStringValue(length) {}
	CInformixStringValue (int4 length, char *value): CInformixAbstractStringValue(length, value) {}
	virtual int2 getType () { return InformixType; }
};

class CInformixLVarCharValue : public CInformixAbstractStringValue
{
public:
	CInformixLVarCharValue (int4 length): CInformixAbstractStringValue(length) {}
	CInformixLVarCharValue (int4 length, char *value): CInformixAbstractStringValue(length, value) {}
	virtual int2 getType () { return SQLLVARCHAR; }
	virtual int2 getXID () { return XID_LVARCHAR; }
	virtual char * getTypeName () { return "lvarchar"; }
	virtual int2 getTypeNameLength () { return sizeof("lvarchar") - 1; }
};


/////////////////////////////////////////////////////////////////////////////
// CInformixAbstractDecimalValue

class CInformixAbstractDecimalValue : public CInformixAbstractValue, private IFetchObserver
{
public:
	CInformixAbstractDecimalValue (int4 length, IFetchSubject *fetchSubject);
	CInformixAbstractDecimalValue (pFMTBcd value);
	virtual int4 getLength ();
	virtual char * getData ();
	virtual double asDouble ();
	virtual FMTBcd& asFMTBcd ();
private:
	virtual void update ();
	int4 _length;
	decimal _value;
	bool _hasDouble;
	double _double;
	bool _hasBcd;
	FMTBcd _bcd;
};

template <int2 InformixType>
class CInformixDecimalValue : public CInformixAbstractDecimalValue
{
public:
	CInformixDecimalValue (int4 length, IFetchSubject *fetchSubject): CInformixAbstractDecimalValue(length, fetchSubject) {}
	CInformixDecimalValue (pFMTBcd value): CInformixAbstractDecimalValue(value) {}
	virtual int2 getType () { return InformixType; }
};


/////////////////////////////////////////////////////////////////////////////
// CInformixDateTimeValue

class CInformixDateTimeValue : public CInformixAbstractValue, private IFetchObserver
{
public:
	CInformixDateTimeValue (int2 qualifier, IFetchSubject *fetchSubject);
	CInformixDateTimeValue (INT32 value);
	CInformixDateTimeValue (DFLOAT value);
	CInformixDateTimeValue (pCTIMESTAMP value);
	virtual int2 getType ();
	virtual int4 getLength ();
	virtual char * getData ();
	operator CTIMESTAMP& ();
private:
	virtual void update ();
	dtime _value;
	bool _isConverted;
	CTIMESTAMP _timestamp;
};


/////////////////////////////////////////////////////////////////////////////
// CInformixIntervalValue

class CInformixIntervalValue : public CInformixAbstractValue, private IFetchObserver
{
public:
	CInformixIntervalValue (int2 qualifier, IFetchSubject *fetchSubject);
	virtual int2 getType ();
	virtual int4 getLength ();
	virtual char * getData ();
	virtual void asString (char *value);
private:
	virtual void update ();
	intrvl _value;
	bool _isConverted;
	char _buffer[INTERVAL_AS_VARCHAR_LENGTH + 1];
};


/////////////////////////////////////////////////////////////////////////////
// CInformixDateValue

class CInformixDateValue : public CInformixAbstractValue
{
public:
	CInformixDateValue ();
	CInformixDateValue (INT32 value);
	virtual int2 getType ();
	virtual int4 getLength ();
	virtual char * getData ();
	operator INT32 ();
private:
	int4 _value;
};


/////////////////////////////////////////////////////////////////////////////
// CInformixInt8Value

class CInformixAbstractInt8Value : public CInformixAbstractValue, private IFetchObserver
{
public:
	CInformixAbstractInt8Value (IFetchSubject *fetchSubject);
	virtual int4 getLength ();
	virtual char * getData ();
	virtual double asDouble ();
	virtual FMTBcd& asFMTBcd ();
private:
	virtual void update ();
	ifx_int8 _value;
	bool _hasDouble;
	double _double;
	bool _hasBcd;
	FMTBcd _bcd;
};

template <int2 InformixType>
class CInformixInt8Value : public CInformixAbstractInt8Value
{
public:
	CInformixInt8Value (IFetchSubject *fetchSubject): CInformixAbstractInt8Value(fetchSubject) {}
	virtual int2 getType () { return InformixType; }
};


/////////////////////////////////////////////////////////////////////////////
// CInformixAbstractLOValue

class CInformixAbstractLOValue : public CInformixAbstractValue
{
public:
	virtual int4 getBlobSize () = 0;
	virtual void getBlobData (int4 length, void *value) = 0;
};


/////////////////////////////////////////////////////////////////////////////
// CInformixSimpleLOValue

class CInformixAbstractSimpleLOValue : public CInformixAbstractLOValue
{
public:
	CInformixAbstractSimpleLOValue (int4 size);
	CInformixAbstractSimpleLOValue (int2 sqltype, int4 size, void *value);
	virtual ~CInformixAbstractSimpleLOValue ();
	virtual int4 getLength ();
	virtual char * getData ();
	virtual int4 getBlobSize ();
	virtual void getBlobData (int4 length, void *value);
private:
	loc_t _value;
};

template <int2 InformixType>
class CInformixSimpleLOValue : public CInformixAbstractSimpleLOValue
{
public:
	CInformixSimpleLOValue (int4 size): CInformixAbstractSimpleLOValue(size) {}
	CInformixSimpleLOValue (int4 size, void *value): CInformixAbstractSimpleLOValue(InformixType, size, value) {}
	virtual int2 getType () { return InformixType; }
};


/////////////////////////////////////////////////////////////////////////////
// CInformixAbstractOpaqueValue

#ifdef WIN32
typedef int (__cdecl *ifx_var_freevar_proc) (void **variable);
extern ifx_var_freevar_proc g_ifx_var_freevar;
#endif

class CInformixAbstractOpaqueValue : public CInformixAbstractValue
{
public:
	CInformixAbstractOpaqueValue ();
	CInformixAbstractOpaqueValue (int4 size, void *value);
	virtual ~CInformixAbstractOpaqueValue ();
	virtual int4 getLength ();
	virtual char * getData ();
	virtual void asString (char *value);
	virtual int4 getBlobSize ();
	virtual void getBlobData (int4 length, void *value);
private:
	void checkConnect ();
	void *_value;
};


/////////////////////////////////////////////////////////////////////////////
// CInformixLVarCharPtrValue

class CInformixLVarCharPtrValue : public CInformixAbstractOpaqueValue
{
public:
	CInformixLVarCharPtrValue () {}
	CInformixLVarCharPtrValue (int4 size, void *value): CInformixAbstractOpaqueValue(size, value) {}
	virtual int2 getType () { return CLVCHARPTRTYPE; }
	virtual int2 getXID () { return XID_LVARCHAR; }
	virtual char * getTypeName () { return "lvarchar"; }
	virtual int2 getTypeNameLength () { return sizeof("lvarchar") - 1; }
};


/////////////////////////////////////////////////////////////////////////////
// CInformixAbstractSmartLOValue

class CInformixAbstractSmartLOValue : public CInformixAbstractLOValue, private IFetchObserver
{
public:
	CInformixAbstractSmartLOValue (IFetchSubject *fetchSubject);
	CInformixAbstractSmartLOValue (int4 size, void *value);
	virtual ~CInformixAbstractSmartLOValue ();
	virtual int2 getType ();
	virtual int4 getLength ();
	virtual char * getData ();
	virtual int4 getBlobSize ();
	virtual void getBlobData (int4 length, void *value);
private:
	mint getDescriptor ();
	virtual void update ();
	ifx_lo_t _value;
	bool _isOpened;
	bool _isMeasured;
	int4 _size;
	mint _descriptor;
};


/////////////////////////////////////////////////////////////////////////////
// CInformixCLOBValue

class CInformixCLOBValue : public CInformixAbstractSmartLOValue
{
public:
	CInformixCLOBValue (IFetchSubject *fetchSubject): CInformixAbstractSmartLOValue (fetchSubject) {}
	CInformixCLOBValue (int4 size, void *value): CInformixAbstractSmartLOValue (size, value) {}
	virtual int2 getXID () { return XID_CLOB; }
	virtual char * getTypeName () { return "clob"; }
	virtual int2 getTypeNameLength () { return sizeof("clob") - 1; }
};


/////////////////////////////////////////////////////////////////////////////
// CInformixBLOBValue

class CInformixBLOBValue : public CInformixAbstractSmartLOValue
{
public:
	CInformixBLOBValue (IFetchSubject *fetchSubject): CInformixAbstractSmartLOValue (fetchSubject) {}
	CInformixBLOBValue (int4 size, void *value): CInformixAbstractSmartLOValue (size, value) {}
	virtual int2 getXID () { return XID_BLOB; }
	virtual char * getTypeName () { return "blob"; }
	virtual int2 getTypeNameLength () { return sizeof("blob") - 1; }
};


/////////////////////////////////////////////////////////////////////////////
// CInformixBooleanValue

class CInformixBooleanValue : public CInformixSimpleValue<int2, SQLBOOL>
{
public:
	CInformixBooleanValue (): CInformixSimpleValue<int2, SQLBOOL>(0) {}
	CInformixBooleanValue (int2 value): CInformixSimpleValue<int2, SQLBOOL>(value) {}
	virtual int2 getXID () { return XID_BOOLEAN; }
	virtual char * getTypeName () { return "boolean"; }
	virtual int2 getTypeNameLength () { return sizeof("boolean") - 1; }
};


/////////////////////////////////////////////////////////////////////////////
// CInformixVariable

class CInformixVariable
{
public:
	CInformixVariable ();
	~CInformixVariable ();
	void initialize (ifx_sqlvar_t *sqlvar);
	int2 getType () const;
	int4 getLength () const;
	CInformixAbstractValue * getValue () const;
	void setValue (CInformixAbstractValue *value);
	bool isNull () const;
	void setNull ();
	char * getName () const;
	int4 getXID () const;
	char * getTypeName () const;
private:
	int2 _isNull;
	CInformixAbstractValue *_value;
	ifx_sqlvar_t *_sqlvar;
};

#endif // __IFXVARIABLE_HPP__
